跳到主要内容

Create by fall on 22 Nov 2022 Recently revised in 10 Feb 2025

脚本文件

使用

bash 可以用于书写批量执行的脚本,或者是 npm 中的脚本(node_modules 下的 .bin 目录中,有三类脚本,分别在不同的环境下执行)

首行内容固定,以 #! 开始,称为 shebang 指令,用于指定运行该脚本的解析器。

命名一个 bash 脚本:hello.sh,并在脚本内填写以下内容

#!/bin/sh
VAR="world"
echo "Hello $VAR"
$ bash hello.sh

输出内容为:Hello world

Shebang 指令是所有脚本语言通用的,也会出现 node 或者其他形式的书写方式。

执行脚本

作为可执行文件执行

# 给所有用户添加执行权限
chmod a+x hello.sh # 同 chmod 755 hello.sh
./hello.sh

指定解析器执行

使用 bash 作为解析器执行 hello.sh

$ bash hello.sh

作为全局命令

# 移动,并把后缀去掉,这样更像命令
mv hello.sh /usr/local/bin/hello
hello
# Hello Shell!

# 创建软连接也可以执行该命令
ln -s ./hello.sh /usr/local/bin/hello

# 命令别名也可以,注意只能在当前窗口中生效
alias hello="bash ~/hello.sh"
hello
# Hello Shell!

注释

# 这是一个内联 Bash 注释
# 多行注释中冒号,空格,引号,缺一不可。
: '
这是 bash 多行注释
bash echo
'

配置

可以在一下位置进行 bash 的全局配置

  • Bash: ~/.bash_profile
  • ZSH: ~/.zshrc

输入输出

输出

  • echo:打印内容的标准输出。
  • printf:格式化输出,类似 C 的 printf 函数。
echo "hello"
printf "保留两位小数:e = %1.2f" $E
# 2.72

通过 > 符号可以将内容输出到文件

echo "老铁,整一个" > file.txt
# >> 表示向文件内追加内容
echo "整一个!" >> file.txt

输入

read:从标准输入读取用户输入

# 展示输入提示,用户输入值被保存到变量name中
read -p "请输入任意值" name

# 利用重定向,从文件中读取输入值
read name1 name2 < file.txt

变量

NAME="Fall"     # 注意:赋值符号前后均不能有空格
echo ${NAME} # => Fall (变量)
echo $NAME # => Fall (变量)
echo "$NAME" # => Fall (变量)
echo '$NAME' # => $NAME (字符串原样输出) 单引号和双引号不同
echo "${NAME}!" # => Fall! (变量)

变量的作用域可以分成三类:

  • 环境变量:能在当前 shell 及其子 shell 中使用,使用 declare -xexport 导出。
  • 全局变量:只能在当前 shell 进程内使用,默认。
  • 局部变量:只能在函数内使用,使用命令 local 声明。

变量除了保存值以外,还可能绑定某些属性,比如 只读、只能存储数值、作用域。

declare 命令可以赋予变量一些特殊的属性。

declare -r CONST_INT=2 # 设置只读变量,同 readonly 命令声明的变量
declare -i a_int=3 # 数字类型变量
declare -x ENV_VAR=value # 设置为环境变量

尽管这看起来像是变量声明,不过也可以作用于已有变量。

var=val
declare -r var

默认参数

系统提供了一些默认参数提供调用

表示描述
$0脚本本身的名称
$1$9参数 1 ... 9
${10}位置参数 10
$#参数数量
$$shell 的进程 id
$*所有参数,作为一个整体
$@所有参数,依次分割
$-当前选项
$_上一个命令的最后一个参数
$?上一个命令的执行结果,0 为成功,其他为失败

假设有如下脚本 test

#!/bin/sh
pink="Ori ddd"
echo $pink
echo $(pwd)
echo $0
echo $1
echo $*

我们通过该方式执行

# 执行该命令
bash test -g -m
# 得到输出为
# Ori ddd
# /e/Full-stuck-study/命令行
# test.sh
# -g
# -g -m

$@$- 的区别

#!/bin/bash
echo "当前使用: \$*:"
for arg in "$*"
do
echo "Hello $arg"
done
echo "当前使用: \$@:"
for arg in "$@"
do
echo "Hello $arg"
done
# 执行命令 sh ./ddd.sh js shell python 
当前使用: $*:
Hello JS shell Python
当前使用: $@:
Hello JS
Hello shell
Hello Python

大括号扩展

echo {A,B}
# A B
echo {A,B}.js
# A.js B.js
{1..5}
# 1 2 3 4 5
{A..F}
# A B C D E F

$(( expression )) # 表达式计算后的值

参数扩展

代码描述
${FOO%suffix}删除后缀
${FOO#prefix}删除前缀
${FOO%%suffix}去掉长后缀
${FOO##prefix}删除长前缀
${FOO/from/to}替换第一个匹配项
${FOO//from/to}全部替换
${FOO/%from/to}替换后缀
${FOO/#from/to}替换前缀
表示描述
${FOO:0:3}字符串或数组的切片
${FOO:(-3):3}从右边开始的子串
${#FOO}参数 FOO 的长度
${FOO:-val}$FOO,如果未设置,则为 val
${FOO:=val}如果未设置,则将 $FOO 设置为 val
${FOO:+val}val 如果设置了$FOO
${FOO:?message}如果 $FOO 未设置,则显示消息并退出
foo='you are beautiful'
echo ${foo%ful}

pink="what"
echo ${#pink} # 4



函数

定义函数

#!/bin/sh
pink="Ori"
get_name() {
echo "John ${pink}"
}
echo "You are $(get_name)"
# 执行结果
# You are John 执行结果

其中,函数的定义也可以写为

function get_name(){
echo "John $pink"
}
# 函数的执行必须通过 $() 或者 `` 进行包裹
$(get_name)
`get_name`
# 二者等价

命令替换

#!/bin/sh
# 如果想要执行一些命令,可以使用 `command` 或者 $(command) 使用命令 command,并且两者可以替换
echo `pwd` # 等同于 $(pwd)
# 输出:
# /e/Full-stuck-study/命令行
echo "where am i $(pwd)"
echo "where am i `pwd`"

执行流程控制

顺序执行命令,使用 ; 进行分割

# 一次性输入多个命令
command1; command2; command3

&&||

command && command1 || command2
# command 执行为 true ,执行 command1 否则执行 command2

条件句

test 命令是一个专门用于条件判断的内置命令,它支持一系列条件表达式,当条件成立时退出码为 0,不成立时为 1。

test expr
# 或者使用简写
[ expr ]
# 还有一种拓展的test,在原有的基础上支持了正则匹配
[[ expr ]]
#!/bin/sh
string="wtf"
# string="" # 为空时,也为 false
if [ -z "$string" ]; then
echo "String is empty"
elif [ -n "$string" ]; then
echo "String is not empty"
fi

find

if [ -d "data/" ];then
echo "dir exits"
else
echo "dir not exits"
fi

参考文章

作者链接
jaywcjlovehttps://github.com/jaywcjlove/reference/blob/main/docs/bash.md
czpcalmhttps://juejin.cn/post/7130983293347954718
czpcalmhttps://juejin.cn/post/7130982053528469511